/*
* Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved.
*/
package jsystem.treeui.suteditor.planner;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import javax.swing.JTable;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import jsystem.framework.FrameworkOptions;
import jsystem.framework.JSystemProperties;
import jsystem.framework.common.CommonResources;
import jsystem.framework.scenario.ParameterProvider;
import jsystem.framework.scenario.ValidationError;
import jsystem.runner.loader.LoadersManager;
import jsystem.treeui.sobrows.SOProcess;
import jsystem.treeui.suteditor.planner.SutTreeNode.NodeType;
import jsystem.treeui.utilities.CellEditorModel;
import jsystem.utils.StringUtils;
import jsystem.utils.XmlUtils;
import jsystem.utils.beans.BeanElement;
import jsystem.utils.beans.BeanUtils;
import jsystem.utils.beans.CellEditorType;
import org.apache.xpath.XPathAPI;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import com.thoughtworks.qdox.JavaDocBuilder;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
/**
* The SUT planner model is used to build the SUT tree table, and
* support operation on the tree table.
*
* @author Michael Oziransky
*/
public class SutTreeTableModel extends AbstractTreeTableModel implements CellEditorModel {
private static final long serialVersionUID = -9145668070975963430L;
private static final String SUT_TAGS_COLUMN_NAME = "Sut tags";
private static final String ACTUAL_VALUE_COLUMN_NAME = "Actual value";
private static final String CLASS_TAG = "class";
private static final String SUT_TAG = "sut";
// Names of the columns.
static protected String[] cNames = { SUT_TAGS_COLUMN_NAME, "Class name",
"Default value", ACTUAL_VALUE_COLUMN_NAME, "Java documentation" };
// Types of the columns.
static protected Class<?>[] cTypes = { TreeTableModel.class, String.class,
String.class, String.class, String.class, Enum.class };
/**
* The root of the tree
*/
private SutTreeNode root;
/**
* The original document that was the base for this model
*/
private Document originalDocument;
private static JavaDocBuilder builder;
/**
* All the system objects implementations found
*/
private ArrayList<String> systemObjectList = null;
private String filter = null;
private FilterType filterType = FilterType.ALL;
/**
* Indicates whether the model has been changed
*/
private boolean hasChanged;
/**
* Array List of <code>Document</code> elements.
* This list holds all non system objects elements.
*/
private static ArrayList<Element> nonModelElements = null;
static HashSet<String> groups = new HashSet<String>();
/**
* We have to implement this
*/
public SutTreeTableModel() {
super(new SutTreeNode(NodeType.ROOT, ""));
}
/**
* Create a Sut tree model based on XML document
* @param document
* @return SutTreeTableModel
* @throws Exception
*/
public static SutTreeTableModel createNewModel(Document document) throws Exception {
// Handle the javadoc reader
builder = null;
groups = new HashSet<String>();
groups.add("");
try {
File testDir = new File(JSystemProperties.getInstance().getPreference(FrameworkOptions.RESOURCES_SOURCE_FOLDER));
builder = SOProcess.initBuilder(CommonResources.getAllOptionalLibDirectories(), new String[] {
testDir.getAbsolutePath(), (new File(testDir.getParentFile(), "src")).getAbsolutePath() });
} catch (Exception exception) {
}
// Handle the xml parsing
SutTreeNode root = new SutTreeNode(NodeType.ROOT, "");
Element sutTag = null;
// If the sut tag is not found (probably a new doc), create it
if (XmlUtils.isSubTagExist(document, SUT_TAG)) {
// We have a sut tag. Find it and set it for the root sut node.
NodeList nodeList = document.getChildNodes();
for (int index = 0; index < nodeList.getLength(); index++) {
Node currentNode = nodeList.item(index);
if (currentNode instanceof Element) {
if (((Element) currentNode).getTagName().equals(SUT_TAG)) {
sutTag = (Element) currentNode;
break;
}
}
}
// Set the root element
root.setElement(sutTag);
} else {
sutTag = document.createElement(SUT_TAG);
document.appendChild(sutTag);
root.setElement(sutTag);
}
// Create a list of all non system object elements
nonModelElements = new ArrayList<Element>();
NodeList list = XPathAPI.selectNodeList(document, "/sut/*[not(class)]");
for (int index = 0; index < list.getLength(); index++) {
Node currentNode = list.item(index);
if (currentNode instanceof Element) {
nonModelElements.add((Element)currentNode);
}
}
// Create a full model of all system objects
root = createFullModel(root, document, builder);
return new SutTreeTableModel(root, document);
}
private static void addBeanGroupToGenericGroup(BeanElement element){
if(element != null){
String[] groupsString = element.getGroups();
if(groupsString != null){
for(String g: groupsString)
groups.add(g);
}
}
}
/**
* Utility function to build the real tree table model. This is done by going
* recursively all over the XML document.
* The idea is:
* 1. Find all sub system objects
* 2. Find all fields that are not in the sut
* 3. Find all default values
* 4. Update the document to contain all new fields
* @param root
* @param doc
* @param nonModelDoc
* @return new SutTreeNode
* @throws Exception
*/
private static SutTreeNode createFullModel(SutTreeNode root, Document doc, JavaDocBuilder builder) throws Exception {
// If the parent is the root node search for all the system object
// found under the sut tag.
if (root.getType() == NodeType.ROOT) {
NodeList list = XPathAPI.selectNodeList(doc, "/sut/*[class]");
for (int index = 0; index < list.getLength(); index++) {
Node currentNode = list.item(index);
if (currentNode instanceof Element) {
SutTreeNode node = new SutTreeNode(NodeType.MAIN_SO, currentNode.getNodeName());
if (XmlUtils.isSubTagExist(currentNode, CLASS_TAG)) {
node.setClassName(XmlUtils.getSubTagValue(currentNode, CLASS_TAG));
}
node.setElement((Element) currentNode);
root.add(createFullModel(node, doc, builder));
}
}
} else {
Element element = root.getElement();
if (!XmlUtils.isSubTagExist(element, CLASS_TAG)) { // not a system object
// continue
return null;
}
String className = XmlUtils.getSubTagValue(element, CLASS_TAG);
Class<?> systemObjectClass = LoadersManager.getInstance().getLoader()
.loadClass(className);
ArrayList<Field> potentialFields = SystemObjectBrowserUtils
.getSystemObjectField(systemObjectClass);
// Go over all the potential fields and find once that not defined
for (Field currentField : potentialFields) {
if (!XmlUtils.isSubTagExist(element, currentField.getName())) {
SutTreeNode subField;
String soClassName = null;
if (currentField.getType().isArray()) {
subField = new SutTreeNode(NodeType.EXTENTION_ARRAY_SO, currentField.getName());
soClassName = currentField.getType().getComponentType().getName();
subField.setArraySuperClassName(soClassName);
} else {
subField = new SutTreeNode(NodeType.EXTENTION_SO, currentField.getName());
soClassName = currentField.getType().getName();
}
// Set the name of the class
subField.setClassName(soClassName);
// Add the sut node to the tree
root.add(subField);
}
}
HashMap<String, BeanElement> map = BeanUtils.getBeanMap(systemObjectClass, false, true, BeanUtils.getBasicTypes());
// Go over all the existing nodes they can be sub
// system objects or properties
NodeList nodeList = element.getChildNodes();
for (int index = 0; index < nodeList.getLength(); index++) {
Node currentNode = nodeList.item(index);
if (!(currentNode instanceof Element)) {
continue;
}
Element currentElement = (Element)currentNode;
String fieldName = currentElement.getNodeName();
// Look for tags
if (!XmlUtils.isSubTagExist(currentNode, CLASS_TAG)) {
// Skip all class tags
if (currentElement.getNodeName().equals(CLASS_TAG)) {
continue;
}
// Create new sut node
SutTreeNode tagNode = new SutTreeNode(NodeType.TAG, fieldName);
// Set the element for this node
Node firstNode = currentNode.getFirstChild();
String actualValue = new String("");
if (firstNode != null && firstNode instanceof Text) {
actualValue = ((Text)firstNode).getData().toString();
}
tagNode.setElement(currentElement);
tagNode.setActualValue(actualValue);
// Find the default value and set it
String setter = "set" + StringUtils.firstCharToUpper(fieldName);
String defaultValue = SystemObjectBrowserUtils
.getDefaultValueFor(systemObjectClass, setter);
addBeanGroupToGenericGroup(map.get(fieldName));
tagNode.setBean(map.get(fieldName));
if (defaultValue == null) {
defaultValue = new String("N/A");
}
tagNode.setDefaultValue(defaultValue);
tagNode.setJavadoc(getJavadoc(builder, className, setter));
// Add to the tree
root.add(tagNode);
} else {
// if it as a class tag it's system object
SutTreeNode sub_so;
String atrib = currentElement.getAttribute("index");
String nodeName = currentElement.getNodeName();
if (atrib == null || atrib.equals("")) {
sub_so = new SutTreeNode(NodeType.SUB_SO, nodeName);
} else {
sub_so = new SutTreeNode(NodeType.ARRAY_SO, nodeName);
sub_so.setIndex(Integer.parseInt(atrib));
Field field = systemObjectClass.getField(nodeName);
if(field != null && field.getType().isArray()){
sub_so.setArraySuperClassName(field.getType().getComponentType().getName());
}
}
sub_so.setElement(currentElement);
// Set the name of the class
sub_so.setClassName(XmlUtils.getSubTagValue(currentNode, CLASS_TAG));
// See if there is underlying objects
root.add(createFullModel(sub_so, doc, builder));
}
}
// Go over all the setter and if not already set add it as a optional tag
Collection<BeanElement> beansCollections = map.values();
for (BeanElement currentBean : beansCollections) {
String setter = currentBean.getSetMethod().getName();
if (SystemObjectBrowserUtils.isSystemObjectSetMethod(setter)) {
continue;
}
String setterTag = StringUtils.firstCharToLower(setter
.substring(3)); // remove the set
if (!XmlUtils.isSubTagExist(element, setterTag)) {
// Create new sut node
SutTreeNode optionalTag =
new SutTreeNode(NodeType.OPTIONAL_TAG, setterTag);
String defaultValue = SystemObjectBrowserUtils
.getDefaultValueFor(systemObjectClass, setter);
if (defaultValue == null) {
defaultValue = new String("N/A");
}
optionalTag.setActualValue("");
optionalTag.setDefaultValue(defaultValue);
optionalTag.setJavadoc(getJavadoc(builder, className, setter));
addBeanGroupToGenericGroup(map.get(setterTag));
optionalTag.setBean(map.get(setterTag));
// Add the sut node to the tree
root.add(optionalTag);
}
}
}
return root;
}
/**
* Gets the string representation of the javadoc for a given class
* @param builder
* Javadoc builder
* @param soClass
* Name of the class to get the javadoc for
* @param soMethod
* The method to get the javadoc for
* @return String
* String representation of the javadoc
*/
private static String getJavadoc(JavaDocBuilder builder,
String soClass, String soMethod) {
if (builder == null) {
return null;
}
JavaClass cls = builder.getClassByName(soClass);
JavaClass superCls = null;
if (cls.getSuperJavaClass() != null){
superCls = builder.getClassByName(cls.getSuperJavaClass().getName().toString());
}else {
superCls = builder.getClassByName(cls.getSuperClass().getFullQualifiedName());
}
JavaClass[] interfacesCls = cls.getImplementedInterfaces();
JavaMethod methods[] = cls.getMethods();
// Go over the methods and see if we have the setter one
// that matches the given method name.
// A setter is a method that starts with 'set'
// A setter is a method that has one parameter
for (int index = 0; index < methods.length; index++) {
JavaMethod method = methods[index];
if (method.getName().equals(soMethod) &&
method.getName().startsWith("set") &&
method.getParameters().length == 1) {
StringBuilder buffer = new StringBuilder();
if (method.getComment() != null){
buffer.append(method.getComment());
}
DocletTag[] tags = method.getTags();
if(tags != null && tags.length > 0){
if (buffer.length() > 0){
buffer.append("\n");
}
for(DocletTag doclet: tags){
buffer.append(doclet.getName()).append(": ").append(doclet.getValue());
}
}
if (buffer.length() == 0){
for (JavaClass interfaceCls : interfacesCls) {
JavaMethod interfaceMethods[] = interfaceCls.getMethods();
for (int jndex = 0; jndex < interfaceMethods.length; jndex++){
JavaMethod interfaceMethod = interfaceMethods[jndex];
if (interfaceMethod.getName().equals(method.getName())){
if (interfaceMethod.getParameters().length == 1) {
if (interfaceMethod.getComment() != null){
buffer.append(interfaceMethod.getComment());
}
tags = interfaceMethod.getTags();
if(tags != null && tags.length > 0){
buffer.append("\n");
for(DocletTag doclet: tags){
buffer.append(doclet.getName()).append(": ").append(doclet.getValue());
}
}
}
}
}
}
}
if (buffer.length() == 0){
JavaMethod superMethods[] = superCls.getMethods();
for (int jndex = 0; jndex < superMethods.length; jndex++){
JavaMethod superMethod = superMethods[jndex];
if (superMethod.getName().equals(method.getName())){
if (superMethod.getParameters().length == 1) {
if (superMethod.getComment() != null){
buffer.append(superMethod.getComment());
}
tags = superMethod.getTags();
if(tags != null && tags.length > 0){
buffer.append("\n");
for(DocletTag doclet: tags){
buffer.append(doclet.getName()).append(": ").append(doclet.getValue());
}
}
}
}
}
}
if (buffer.length() == 0){
buffer.replace(0, buffer.length(), "N/A");
}
return buffer.toString();
}
}
return null;
}
/**
* Private constructor. use the <code>createNewModel</code> to create a model.
* @param root the model tree node root.
* @param doc the base document
* @throws Exception
*/
private SutTreeTableModel(TreeNode root, Document doc) throws Exception {
super(root);
this.root = (SutTreeNode)root;
this.originalDocument = doc;
}
/**
* Add a system object to the given parent
*
* @param parent
* Parent to add the system object to
* @param soName
* System object name
* @param className
* System object class name
* @throws Exception
*/
public void addSystemObject(SutTreeNode parent, String soName, String className)
throws Exception {
SutTreeNode newNode = new SutTreeNode(NodeType.MAIN_SO, soName);
// Set the class name
newNode.setClassName(className);
// Add underlying nodes
addSubTree(newNode);
// Notify all
insertNodeInto(newNode, parent, parent.getChildCount());
}
private void insertNodeInto(SutTreeNode newChild,
SutTreeNode parent, int index) {
parent.insert(newChild, index);
modelSupport.fireChildAdded(new TreePath(getPathToRoot(parent)), index,
newChild);
}
private void removeNodeFromParent(SutTreeNode node, boolean recover) throws Exception{
SutTreeNode parent = (SutTreeNode)node.getParent();
if(parent == null){
return;
}
int childIndex = parent.getIndex(node);
if(childIndex < 0){
return;
}
parent.remove(childIndex);
modelSupport.fireChildRemoved(new TreePath(getPathToRoot(parent)), childIndex, node);
Class<?> systemObjectClass = LoadersManager.getInstance().getLoader().loadClass(parent.getClassName());
ArrayList<Field> potentialFields = SystemObjectBrowserUtils.getSystemObjectField(systemObjectClass);
Field originalFiled = null;
// Go over all the potential fields and find once that not defined
for (Field currentField : potentialFields) {
if(currentField.getName().equals(node.getName())){
originalFiled = currentField;
break;
}
}
if(originalFiled != null && recover){
SutTreeNode newNode = null;
if((node.getType() == NodeType.SUB_SO || node.getType() == NodeType.MAIN_SO)){
newNode = new SutTreeNode(NodeType.EXTENTION_SO, originalFiled.getName());
newNode.setClassName(originalFiled.getType().getName());
} else if(node.getType() == NodeType.ARRAY_SO){
newNode = new SutTreeNode(NodeType.EXTENTION_ARRAY_SO, originalFiled.getName());
newNode.setClassName(originalFiled.getType().getComponentType().getName());
}
if(newNode != null){
parent.add(newNode);
modelSupport.fireChildrenAdded(new TreePath(getPathToRoot(parent)), new int[]{childIndex}, new Object[]{newNode});
}
}
}
public SutTreeNode[] getPathToRoot(SutTreeNode aNode) {
List<SutTreeNode> path = new ArrayList<SutTreeNode>();
SutTreeNode node = aNode;
while (node != root) {
path.add(0, node);
node = (SutTreeNode) node.getParent();
}
if (node == root) {
path.add(0, node);
}
return path.toArray(new SutTreeNode[0]);
}
/**
* Removes a system object from given parent
* @param parent
* Parent to remove the system object from
* @throws Exception
*/
public void removeObject(SutTreeNode node, boolean recovery) throws Exception {
// Save the parent node for notification
TreeNode parent = node.getParent();
// If this is an array, update all other indexes
if (node.getType() == NodeType.ARRAY_SO) {
int nodeIndex = 0;
String elementName = node.getName();
Enumeration<?> elements = parent.children();
int arrayCount = 0;
while (elements.hasMoreElements()) {
SutTreeNode te = (SutTreeNode)elements.nextElement();
if (te.getName().equals(elementName)) {
arrayCount++;
}
}
// Remove the node
if(arrayCount == 1){
removeNodeFromParent(node, true & recovery);
} else {
removeNodeFromParent(node, false);
}
// Go over all children and if they are from the same name, update
elements = parent.children();
while (elements.hasMoreElements()) {
SutTreeNode te = (SutTreeNode)elements.nextElement();
if (te.getName().equals(elementName)) {
te.setIndex(nodeIndex);
nodeIndex++;
}
}
} else {
// Remove the node
removeNodeFromParent(node, true);
}
}
/**
* Add a sub system object
* @param node
* System object node
* @param className
* Class name
* @throws Exception when the process fail
*/
public void setSystemObject(SutTreeNode node, String className)
throws Exception {
// Set the class name
node.setClassName(className);
node.setType(NodeType.SUB_SO);
// Add underlying nodes
addSubTree(node);
// Notify all
modelSupport.firePathChanged(new TreePath(getPathToRoot(node)));
}
public void refresh(){
// setRoot(root);
modelSupport.fireTreeStructureChanged(new TreePath(root));
}
public List<ValidationError> getAllPropertyValidationError(){
return null;
}
/**
* Add additional system object to an array of system objects
* @param node
* Node that we need to take as a reference
* @param soName
* Name of the system object
* @param className
* Class name
* @throws Exception
*/
public void addArraySystemObject(SutTreeNode node, String soName, String className)
throws Exception {
int arrayIndex;
SutTreeNode parent = (SutTreeNode)node.getParent();
// Check if this node is extension node
if (node.getType() == NodeType.EXTENTION_ARRAY_SO) {
// This is the first element in the array
arrayIndex = 0;
// We don't need this node anymore
removeObject(node, false);
} else {
// find the last node of this type
node = getLastBrother(node);
arrayIndex = new Integer(node.getIndex()).intValue() + 1;
// arrayIndex = node.getIndex() + 1;
}
// Create a new node that will be appended
SutTreeNode newNode = new SutTreeNode(NodeType.ARRAY_SO, soName);
// Set the class name
newNode.setArraySuperClassName((node.getArraySuperClassName() == null)? node.getClassName(): node.getArraySuperClassName());
newNode.setClassName(className);
newNode.setIndex(arrayIndex);
// Add underlying nodes
addSubTree(newNode);
// Insert the node into the tree
insertNodeInto(newNode, parent, parent.getChildCount());
}
private SutTreeNode getLastBrother(SutTreeNode node){
SutTreeNode parent = (SutTreeNode)node.getParent();
for(int index = 0; index < parent.getChildCount(); index++){
SutTreeNode brother = (SutTreeNode)parent.getChildAt(index);
if(node.getName().equals(brother.getName()) && (brother.getIndex() > node.getIndex())){
node = brother;
}
}
return node;
}
/**
* Return a list of all the system objects implementing a specific class.
* (all abstract will be removed).
* @param typeClassName the class to look implementation for.
* @return a list of implementation names.
* @throws Exception
*/
public ArrayList<String> getSystemObjectsOfType(String typeClassName)
throws Exception {
if (systemObjectList == null) {
systemObjectList = SystemObjectBrowserUtils.getFoundSOs();
}
if (typeClassName == null) {
return systemObjectList;
}
ArrayList<String> listOfType = new ArrayList<String>();
// Filter the general system object list
Class<?> type =
LoadersManager.getInstance().getLoader().loadClass(typeClassName);
for (String object : systemObjectList) {
Class<?> currenrClass =
LoadersManager.getInstance().getLoader().loadClass(object);
if (type.isAssignableFrom(currenrClass)) {
listOfType.add(object);
}
}
return listOfType;
}
/**
* Creates the sub tree from the given root
* @param root
* @throws Exception
*/
private void addSubTree(SutTreeNode root) throws Exception {
Class<?> systemObjectClass = LoadersManager.getInstance().getLoader()
.loadClass(root.getClassName());
ArrayList<Field> potentialFields = SystemObjectBrowserUtils
.getSystemObjectField(systemObjectClass);
// Go over all the potential fields and find once that not defined
for (Field currentField : potentialFields) {
SutTreeNode subField;
String soClassName = null;
if (currentField.getType().isArray()) {
subField = new SutTreeNode(NodeType.EXTENTION_ARRAY_SO, currentField.getName());
soClassName = currentField.getType().getComponentType().getName();
} else {
subField = new SutTreeNode(NodeType.EXTENTION_SO, currentField.getName());
soClassName = currentField.getType().getName();
}
// Set the name of the class
subField.setClassName(soClassName);
// Add the sut node to the tree
root.add(subField);
}
// Go over all the setter and add them as an optional tag
HashMap<String, BeanElement> map = BeanUtils.getBeanMap(systemObjectClass, false, true, BeanUtils.getBasicTypes());
for (BeanElement currentElement : map.values()) {
String setter = currentElement.getSetMethod().getName();
if (SystemObjectBrowserUtils.isSystemObjectSetMethod(setter)) {
continue;
}
String setterTag =
StringUtils.firstCharToLower(setter.substring(3)); // remove the set
// Create new sut node
SutTreeNode optionalTag =
new SutTreeNode(NodeType.OPTIONAL_TAG, setterTag);
// Add a 'default value' text element
String defaultValue = SystemObjectBrowserUtils
.getDefaultValueFor(systemObjectClass, setter);
if (defaultValue == null) {
defaultValue = new String("N/A");
}
// Configure the sut node
optionalTag.setActualValue("");
addBeanGroupToGenericGroup(currentElement);
optionalTag.setBean(currentElement);
optionalTag.setDefaultValue(defaultValue);
optionalTag.setJavadoc(getJavadoc(builder, root.getClassName(), setter));
// Add the sut node to the tree
root.add(optionalTag);
}
}
//
// Some convenience methods.
//
protected Element getSutTag(Object node) {
SutTreeNode sutTagNode = ((SutTreeNode) node);
if (node == null) {
return null;
}
return sutTagNode.getElement();
}
protected Object[] getChildren(Object node) {
SutTreeNode sutTagNode = ((SutTreeNode) node);
ArrayList<Object> children = new ArrayList<Object>();
Object[] objects = sutTagNode.getChildren();
for(Object currentObject: objects){
if(currentObject instanceof SutTreeNode){
if(((SutTreeNode)currentObject).accept(filterType, filter)){
children.add(currentObject);
}
}
}
return children.toArray();
}
//
// The TreeModel interface
//
public int getChildCount(Object node) {
Object[] children = getChildren(node);
return (children == null) ? 0 : children.length;
}
public Object getChild(Object node, int i) {
return getChildren(node)[i];
}
//
// The TreeTableNode interface.
//
public int getColumnCount() {
return cNames.length;
}
public String getColumnName(int column) {
return cNames[column];
}
public Class<?> getColumnClass(int column) {
return cTypes[column];
}
public Object getValueAt(Object node, int column) {
SutTreeNode sutNode = (SutTreeNode)node;
try {
switch (column) {
case 0:
return sutNode.getName();
case 1: //'Class name' column
return sutNode.getClassName();
case 2: //'Default value' column
return sutNode.getDefaultValue();
case 3: //'Actual value' column
return sutNode.getActualValue();
case 4: // 'Java documentation' column
return sutNode.getJavadoc().replaceAll("\n", "\n, ");
}
}
catch (SecurityException se) { }
return null;
}
public void setValueAt(Object aValue, Object node, int column)
{
// If we already got here, this means that we are allowed to edit.
// This means that we are either in sut tag field or actual value field.
// We already know that this is either tag or optional tag
if (getColumnName(column).equals(ACTUAL_VALUE_COLUMN_NAME)) {
SutTreeNode sutNode = (SutTreeNode)node;
ParameterProvider parameterProvider = sutNode.getBean().getParameterProvider();
String stringValue = sutNode.getBean() == null || parameterProvider == null ? aValue.toString() : parameterProvider.getAsString(aValue);
sutNode.setActualValue(stringValue);
// Just in case this is an optional tag, set to regular one
sutNode.setType(NodeType.TAG);
// Notify all
modelSupport.firePathChanged(new TreePath(getPathToRoot(sutNode)));
setHasChanged(true);
}
}
@Override
public boolean isCellEditable(Object node, int column) {
// We allow editing only for tree nodes and actual values
SutTreeNode sutNode = (SutTreeNode)node;
if(!sutNode.isEditable()){
return false;
}
if (getColumnName(column).equals(SUT_TAGS_COLUMN_NAME)) {
return true;
} else if (getColumnName(column).equals(ACTUAL_VALUE_COLUMN_NAME)) {
// We can change values only for
if ((sutNode.getType() == NodeType.TAG) || (sutNode.getType() == NodeType.OPTIONAL_TAG)) {
return true;
}
return false;
}
return false;
}
/**
* Creates a XML representation of this model
* @return Document
* Document containing the XML representation
*/
public void toXml() {
// Lets remove the first not of the document and all its children
NodeList nodeList = originalDocument.getChildNodes();
for (int index = 0; index < nodeList.getLength(); index++) {
Node currentNode = nodeList.item(index);
if (currentNode instanceof Element) {
if (((Element) currentNode).getTagName().equals(SUT_TAG)) {
originalDocument.removeChild(currentNode);
break;
}
}
}
// Serialize the model to the file
toXml(root, null, originalDocument);
// Append all non model elements to the document
for (Element currentElement : nonModelElements) {
Element newElement = originalDocument.createElement(currentElement.getNodeName());
NodeList childNodeList = currentElement.getChildNodes();
for (int index = 0; index < childNodeList.getLength(); index++) {
newElement.appendChild(childNodeList.item(index));
}
NodeList list = originalDocument.getElementsByTagName(SUT_TAG);
Node currentNode = list.item(0);
currentNode.appendChild(newElement);
}
}
private void toXml(SutTreeNode node, Element parentElement, Document doc) {
NodeType type = node.getType();
// We are interested only in specific types
if ((type != NodeType.MAIN_SO) && (type != NodeType.SUB_SO) &&
(type != NodeType.ARRAY_SO) && (type != NodeType.TAG) && (type != NodeType.ROOT))
{
return;
}
Element newElement = null;
Element classElement = null;
if (type == NodeType.ROOT) {
// This is a special case, create the root element
newElement = doc.createElement(SUT_TAG);
newElement.setAttribute("validators", node.getElement().getAttribute("validators"));
} else {
newElement = doc.createElement(node.getName());
}
SutTreeNode children[] = (SutTreeNode[])node.getChildren();
switch (type) {
case ROOT:
for (int index = 0; index < children.length; index++) {
toXml(children[index], newElement, doc);
}
break;
case MAIN_SO:
case SUB_SO:
// For all system objects we need to add a class
classElement = doc.createElement(CLASS_TAG);
classElement.appendChild(doc.createTextNode(node.getClassName()));
newElement.appendChild(classElement);
for (int index = 0; index < children.length; index++) {
toXml(children[index], newElement, doc);
}
break;
case ARRAY_SO:
// This is an system object element in an array, add index attribute
newElement.setAttribute("index", Integer.toString(node.getIndex()));
// For all system objects we need to add a class
classElement = doc.createElement(CLASS_TAG);
classElement.appendChild(doc.createTextNode(node.getClassName()));
newElement.appendChild(classElement);
// Now do the same for all children
for (int index = 0; index < children.length; index++) {
toXml(children[index], newElement, doc);
}
break;
case TAG:
newElement.appendChild(doc.createTextNode(node.getActualValue()));
break;
}
if (type == NodeType.ROOT) {
// This is a special case of a first child;
// connect directly to the document
doc.appendChild(newElement);
} else {
// Connect the new nodes to the parent element
parentElement.appendChild(newElement);
}
}
public String getFilter() {
return filter;
}
public void setFilter(String filter) {
this.filter = filter;
}
public void setHasChanged(boolean hasChanged) {
this.hasChanged = hasChanged;
}
public boolean getHasChanged() {
return hasChanged;
}
public FilterType getFilterType() {
return filterType;
}
public void setFilterType(FilterType filterType) {
this.filterType = filterType;
}
@Override
public int getIndexOfChild(Object parent, Object child) {
return ((SutTreeNode)parent).getIndex((SutTreeNode)child);
}
@Override
public CellEditorType getEditorType(JTable table, int row, int column) {
SutTreeNode node = getTreeNodeForRow(row, table);
if(node.getBean() != null){
return BeanUtils.getBeanType(node.getBean());
}
return CellEditorType.STRING;
}
@Override
public String getLastValidationMessage() {
// TODO Auto-generated method stub
return null;
}
public Document getDocument(){
return originalDocument;
}
@Override
public String[] getOptions(JTable table, int row, int column) {
SutTreeNode node = getTreeNodeForRow(row, table);
if(node.getBean() != null){
return node.getBean().getOptions();
}
return null;
}
@Override
public ParameterProvider getProvider(JTable table, int row, int column) {
SutTreeNode node = getTreeNodeForRow(row, table);
if (node.getBean() != null) {
return node.getBean().getParameterProvider();
}
return null;
}
@Override
public Class<?> getCellType(JTable table, int row, int column) {
SutTreeNode node = getTreeNodeForRow(row, table);
if (node.getBean() != null) {
return node.getBean().getType();
}
return null;
}
@Override
public boolean isValidData(JTable table, int row, int column,
Object enteredValue) {
return true;
}
private static SutTreeNode getTreeNodeForRow(int row, JTable table){
return (SutTreeNode)((JXTreeTable)table).getPathForRow(row).getLastPathComponent();
}
public void moveUp(SutTreeNode selectedNode) {
SutTreeNode parent = (SutTreeNode)selectedNode.getParent();
SutTreeNode upperNode = (SutTreeNode)parent.getChildBefore(selectedNode);
int currentIndex = parent.getIndex(selectedNode);
parent.remove(currentIndex);
TreePath parentPath = new TreePath(parent.getPath());
if(selectedNode.getType() == NodeType.ARRAY_SO){
int index = selectedNode.getIndex();
selectedNode.setIndex(upperNode.getIndex());
upperNode.setIndex(index);
}
modelSupport.fireChildRemoved(parentPath, currentIndex, selectedNode);
parent.insert(selectedNode, currentIndex - 1);
modelSupport.fireChildAdded(parentPath, currentIndex - 1, selectedNode);
}
public void moveDown(SutTreeNode selectedNode) {
SutTreeNode parent = (SutTreeNode)selectedNode.getParent();
SutTreeNode downNode = (SutTreeNode)parent.getChildAfter(selectedNode);
int currentIndex = parent.getIndex(selectedNode);
parent.remove(currentIndex);
TreePath parentPath = new TreePath(parent.getPath());
if(selectedNode.getType() == NodeType.ARRAY_SO){
int index = selectedNode.getIndex();
selectedNode.setIndex(downNode.getIndex());
downNode.setIndex(index);
}
modelSupport.fireChildRemoved(parentPath, currentIndex, selectedNode);
parent.insert(selectedNode, currentIndex + 1);
modelSupport.fireChildAdded(parentPath, currentIndex + 1, selectedNode);
}
public boolean canMoveUp(SutTreeNode node) {
if(node.getParent() == null){
return false;
}
SutTreeNode before = (SutTreeNode)((SutTreeNode)node.getParent()).getChildBefore(node);
if(before == null || before.getType() != node.getType()){
return false;
}
return true;
}
public boolean canMoveDown(SutTreeNode node) {
if(node.getParent() == null){
return false;
}
SutTreeNode after = (SutTreeNode)((SutTreeNode)node.getParent()).getChildAfter(node);
if(after == null || after.getType() != node.getType()){
return false;
}
return true;
}
}